package com.mugu.ipclient;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class IpClient {

	private final static String SERVER_IP = "172.16.12.11";
	private final static int SERVER_CONTROL_PORT = 5300;
	private final static int SERVER_REFRESH_PORT = 5301;
	private final static int HOST_CONTROL_PORT = 5200;
	private final static int HOST_REFRESH_PORT = 5201;

	private final static int TIME_SOCKET_TIMEOUT = 3 * 1000;
	public final static int TIME_REFRESH_ONLINE_INTERVAL = 15 * 1000;

	private final static int MAX_SEND_NUM = 3;

	private DatagramSocket cmdSocket;
	private DatagramSocket refreshSocket;
	private InetAddress ServerAddress;

	private ContralCmd mContralCmd;
	private RefreshCmd mRefreshCmd;

	private double flow;
	private double money;

	private boolean isLogin = false;
	private boolean isSetUserInfo = false;

	public IpClient() {
		initNet();
	}

	private void initNet() {
		try {
			cmdSocket = new DatagramSocket(HOST_CONTROL_PORT);
			refreshSocket = new DatagramSocket(HOST_REFRESH_PORT);
			cmdSocket.setSoTimeout(TIME_SOCKET_TIMEOUT);
			refreshSocket.setSoTimeout(TIME_SOCKET_TIMEOUT);
			ServerAddress = InetAddress.getByName(SERVER_IP);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}

	private String username;
	private String password;

	public void setUserInfo(String userName, String password) {
		mContralCmd = new ContralCmd(userName, password);
		mRefreshCmd = new RefreshCmd(userName, 0);
		isSetUserInfo = true;

		username = userName;
		this.password = password;
	}

	public synchronized String getNews() throws RefreshFaileException {
		try {
			byte[] packet = sendTo(refreshSocket,
					RefreshCmd.get_refresh_get_news_packet(), ServerAddress,
					SERVER_REFRESH_PORT);
			RefreshPacketModel model = RefreshCmd
					.check_refresh_get_news_reply(packet);
			if (model == null) {
				throw new RefreshFaileException("服务器无响应");
			}
			return model.getStr4();
		} catch (IOException e) {
			throw new RefreshFaileException("网络连接失败");
		}
	}

	public synchronized String login() throws LoginFaileException {
		if (!isSetUserInfo) {
			throw new LoginFaileException("您还没有设置用户名和密码");
		}
		byte[] packet1;
		try {
			packet1 = sendTo(cmdSocket, mContralCmd.get_login_userid_packet(),
					ServerAddress, SERVER_CONTROL_PORT);

			if (mContralCmd.check_login_userid_reply(packet1)) {
				byte[] packet2 = sendTo(cmdSocket,
						mContralCmd.get_login_password_packet(), ServerAddress,
						SERVER_CONTROL_PORT);
				CMDPacketModel model = mContralCmd
						.check_login_password_reply(packet2);
				if (model == null) {
					throw new LoginFaileException("服务器无响应");
				}
				if (model.getResult() != 0) {
					throw new LoginFaileException(model.getStr4());
				}
				mRefreshCmd.setRefrshKey(mContralCmd.getKey());
				isLogin = true;
				System.out.println(username + "   " + password);
				refresh0a();
				return model.getStr4();
			} else {
				throw new LoginFaileException("服务器无响应");
			}
		} catch (IOException e) {
			throw new LoginFaileException("网络连接失败");
		}
	}

	public synchronized String logout() throws LogoutFaileException {
		if (!isLogin) {
			throw new LogoutFaileException("您还没有登录");
		}
		byte[] packet1;
		try {
			packet1 = sendTo(cmdSocket, mContralCmd.get_logout_userid_packet(),
					ServerAddress, SERVER_CONTROL_PORT);

			if (mContralCmd.check_logout_userid_reply(packet1)) {
				byte[] packet2 = sendTo(cmdSocket,
						mContralCmd.get_logout_password_packet(),
						ServerAddress, SERVER_CONTROL_PORT);
				CMDPacketModel model = mContralCmd
						.check_logout_password_reply(packet2);
				if (model == null) {
					throw new LogoutFaileException("服务器无响应");
				}
				if (model.getResult() != 0) {
					throw new LogoutFaileException(model.getStr4());
				}
				mContralCmd = null;
				mRefreshCmd = null;
				isLogin = false;
				return model.getStr4();
			} else {
				throw new LogoutFaileException("服务器无响应");
			}
		} catch (IOException e) {
			throw new LogoutFaileException("网络连接失败");
		}
	}

	private boolean refresh0a() {
		byte[] packet;
		try {
			packet = sendTo(refreshSocket, mRefreshCmd.get_refresh_0a_packet(),
					ServerAddress, SERVER_REFRESH_PORT);
			if (!mRefreshCmd.check_refresh_0a_reply(packet)) {
				return false;
			}
		} catch (IOException e) {
			return false;
		}
		return true;

	}

	public synchronized String refreshOnline() throws RefreshFaileException {
		if (!isLogin) {
			throw new RefreshFaileException("您还没有登录");
		}
		byte[] packet;
		try {
			packet = sendTo(refreshSocket,
					mRefreshCmd.get_refresh_online_packet(), ServerAddress,
					SERVER_REFRESH_PORT);

			RefreshPacketModel model = mRefreshCmd
					.check_refresh_online_reply(packet);
			if (model == null) {
				throw new RefreshFaileException("服务器无响应");
			}
			flow = model.getFlow();
			money = model.getMoney();
			if (money < 0.01) {
				throw new RefreshFaileException("您的钱不够了");
			}
			return model.getMsg();
		} catch (IOException e) {
			throw new RefreshFaileException("网络连接失败");
		}
	}

	public double getFlow() {
		return flow;
	}

	public double getMoney() {
		return money;
	}

	public void setLogin(boolean isLogin) {
		this.isLogin = isLogin;
	}

	public boolean isLogin() {
		return isLogin;
	}

	public boolean isSetUserInfo() {
		return isSetUserInfo;
	}

	private byte[] sendTo(DatagramSocket sockets, byte[] data,
			InetAddress address, int port) throws IOException {
		DatagramPacket packet = new DatagramPacket(data, data.length, address,
				port);

		byte[] resultBuf = new byte[data.length];
		DatagramPacket receive = new DatagramPacket(resultBuf, resultBuf.length);
		int tries = 0; // 重发数据的次数
		boolean receivedResponse = false; // 是否接收到数据的标志位
		// 直到接收到数据，或者重发次数达到预定值，则退出循环

		while (!receivedResponse && tries < MAX_SEND_NUM) {
			// 发送数据
			sockets.send(packet);
			try {
				// 接收从服务端发送回来的数据
				sockets.receive(receive);
				// 如果接收到的数据不是来自目标地址，则抛出异常
				if (!receive.getAddress().equals(address)) {
					throw new IOException(
							"Received packet from an umknown source");
				}
				// 如果接收到数据。则将receivedResponse标志位改为true，从而退出循环
				receivedResponse = true;
			} catch (InterruptedIOException e) {
				// 如果接收数据时阻塞超时，重发并减少一次重发的次数
				tries++;
			}
		}
		return receive.getData();
	}

	private String getInfoFormResultCode(int result) {
		String info = null;
		switch (result) {
		case 0x1:
			info = "your ip needn\'t use ipclient.";
			break;
		case 0xa:
			info = "your account is expired.";
			break;
		case 0xb:
			info = "your account is disabled.";
			break;
		case 0x14:
			info = "your account has not enough money.";
			break;
		case 0x15:
			info = "your accont has not available hours in this month.";
			break;
		case 0x16:
			info = "your account has not available flow in this mouth.";
			break;
		case 0x19:
			info = "your account cannot be used in this IP.";
			break;
		case 0x1e:
			info = "your account cannot be used in this time.";
			break;
		case 0x1f:
			info = "please dial later.";
			break;
		case 0x20:
			info = "too many users are using this account now.";
			break;
		case 0x21:
			info = "ipclient cannot be used for your account.";
			break;
		case 0x22:
			info = "please dial later.";
			break;
		case 0x63:
			info = "userid or password error.";
			break;
		default:
			info = "error! not such result code!";
			break;
		}
		return info;
	}

}

class LoginFaileException extends Exception {

	private String message;

	public LoginFaileException(String string) {
		super(string);
		message = string;
	}

	@Override
	public String getMessage() {
		return message;
	}

}

class RefreshFaileException extends Exception {
	private String message;

	public RefreshFaileException(String string) {
		super(string);
		message = string;
	}

	@Override
	public String getMessage() {
		return message;
	}
}

class LogoutFaileException extends Exception {
	private String message;

	public LogoutFaileException(String string) {
		super(string);
		message = string;
	}

	@Override
	public String getMessage() {
		return message;
	}
}
